﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Diagnostics;
using System.IO;


namespace TCP_UDP_client_server_test
{


    class UDPServer
    {
        private static int port = 6000;
        private static UdpClient udpListener;
        private static Int16 framePeriod;
        private static int frameSize;

        private static string logComment;

        private static List<TimeSpan> frameArrivalTime = new List<TimeSpan>();
        private static List<Int32> frameNumbers = new List<Int32>();
        private static Stopwatch stopWatch = new Stopwatch();
        private static bool run = true;

        private static void GetPort()
        {
            bool portAcquired = false;
            while (!(portAcquired))
            {
                Console.WriteLine("Port to connect to [{0}]: ", port);
                string portInput = Console.ReadLine();

                if (portInput.Length > 0)
                {
                    int dummy;
                    if (int.TryParse(portInput, out dummy))
                    {
                        if ((dummy < 65535) && (dummy > 1024))
                        {
                            port = dummy;
                            portAcquired = true;
                        }
                    }
                }
                else
                {
                    portAcquired = true;
                }
            }
        }

        public static void listen()
        {
            GetPort();

            IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 0);


            Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);

            Console.Write("Very short description of event (used part of log file name):");
            logComment = Console.ReadLine();
            


            byte[] dataNumber = new byte[4];

            stopWatch.Start();
            udpListen();
            
            
            try
            {
                while (run)
                {
                    byte[] frame = udpListener.Receive(ref ipEndPoint);
                    frameArrivalTime.Add(stopWatch.Elapsed);

                    frameSize = frame.Length;

                    byte[] frameNumBuffer = new byte[4];
                    Array.Copy(frame, 0, frameNumBuffer, 0, 4);

                    byte[] framePeriodBuffer = new byte[2];
                    Array.Copy(frame, 4, framePeriodBuffer, 0, 2);

                    framePeriod = BitConverter.ToInt16(framePeriodBuffer, 0);

                    Int32 frameNum = BitConverter.ToInt32(frameNumBuffer, 0);
                    frameNumbers.Add(frameNum);
                }

            }
            catch (System.IO.IOException e)
            {
                //it seems easiest and most realiable way to tell if the client disconnected is if an error is thrown when attempting to read/write to the stream

            }
        }

        static void saveFrameNumTiming()
        {

            if (frameNumbers.Count > 1)
            {
                string fileName = "UDP - " + logComment + " - " + DateTime.Now.TimeOfDay.ToString().Replace(':', '.') + ".log";
                string fullFilePath = String.Format("{0}\\{1}", Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), fileName);

                StreamWriter file = File.AppendText(fullFilePath);


                file.WriteLine(String.Format("Data Size (bytes): {0}  Data Period (ms): {1}", frameSize, framePeriod));
                file.WriteLine(String.Format("First frame:{0}  Last frame:{1}", frameNumbers[0], frameNumbers[frameNumbers.Count - 1]));

                int receivedFrames = frameNumbers.Count;
                int missedFrames = (frameNumbers[frameNumbers.Count - 1] - frameNumbers[0]) - receivedFrames + 1;

                file.WriteLine(String.Format("Frames received:{0}  Frames missed:{1}", receivedFrames, missedFrames));


                for (int ii = 1; ii < frameNumbers.Count; ii++)
                {
                    file.WriteLine("{0} {1}", frameNumbers[ii], ( frameArrivalTime[ii] - frameArrivalTime[ii-1] )  );
                }

                file.Close();

            }

            
            


        }

        static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
        {
            run = false;
            saveFrameNumTiming();
            udpStop();
        }

        private static void udpListen()
        {
            udpListener = new UdpClient(port);
            
        }

        private static void udpStop()
        {
            udpListener.Close();
        }



    }
}
